/**
 * AI推理工作器
 * EndoSight-UC 医疗AI系统
 *
 * 异步处理医学图像AI推理任务
 * 支持多进程并发和错误恢复
 */

import queueManager from '../config/queueConfig.js';
import aiInferenceService from '../services/aiInferenceService.js';
import structuredLogger from '../utils/structuredLogger.js';
import auditService from '../services/auditService.js';
import { QueueType, QueuePriority } from '../config/queueConfig.js';
import db from '../config/database.js';
import winston from 'winston';
import { Worker } from 'worker_threads';
import os from 'os';
import path from 'path';
import { fileURLToPath } from 'url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

// 配置日志记录器
const logger = winston.createLogger({
  level: 'info',
  format: winston.format.combine(
    winston.format.timestamp(),
    winston.format.json()
  ),
  transports: [
    new winston.transports.Console({
      format: winston.format.simple()
    }),
    new winston.transports.File({
      filename: 'logs/ai-inference-worker.log',
      level: 'info'
    })
  ]
});

/**
 * AI推理工作器主类
 */
class AIInferenceWorker {
  constructor() {
    this.isRunning = false;
    this.workers = [];
    this.maxWorkers = Math.min(os.cpus().length, 4); // 最多4个工作进程
    this.processedJobs = 0;
    this.failedJobs = 0;
    this.startTime = null;
    this.queue = null;
  }

  /**
   * 启动AI推理工作器
   */
  async start() {
    try {
      logger.info('正在启动AI推理工作器...', {
        maxWorkers: this.maxWorkers,
        nodeVersion: process.version,
        platform: os.platform(),
        arch: os.arch()
      });

      // 获取AI推理队列
      this.queue = queueManager.getQueue(QueueType.AI_INFERENCE);
      if (!this.queue) {
        logger.warn('AI推理队列未初始化，检查Redis连接状态');
        if (!queueManager.redisAvailable) {
          logger.warn('Redis不可用，AI推理工作器将以降级模式运行');
          this.isRunning = true;
          this.startTime = Date.now();
          return;
        }
        throw new Error('AI推理队列未初始化');
      }

      // 设置队列处理器
      this.setupQueueProcessor();

      // 启动工作进程池
      await this.startWorkerPool();

      this.isRunning = true;
      this.startTime = Date.now();

      logger.info('✅ AI推理工作器启动成功', {
        workerCount: this.workers.length,
        maxWorkers: this.maxWorkers,
        pid: process.pid
      });

      // 设置优雅关闭
      this.setupGracefulShutdown();

      return true;
    } catch (error) {
      logger.error('AI推理工作器启动失败:', error);
      throw error;
    }
  }

  /**
   * 设置队列处理器
   */
  setupQueueProcessor() {
    // 基础处理器配置
    const processorOptions = {
      concurrency: this.maxWorkers,
      settings: {
        stalledInterval: 30000,  // 30秒检查停滞任务
        maxStalledCount: 1
      }
    };

    // 注册处理器
    this.queue.process('medical-image-analysis', this.maxWorkers, async (job) => {
      return await this.processAIInferenceJob(job);
    });

    this.queue.process('urgent-analysis', 1, async (job) => {
      return await this.processUrgentInferenceJob(job);
    });

    this.queue.process('batch-analysis', 2, async (job) => {
      return await this.processBatchInferenceJob(job);
    });

    // 队列事件监听
    this.queue.on('completed', (job, result) => {
      this.processedJobs++;
      this.logJobCompletion(job, result);
    });

    this.queue.on('failed', (job, error) => {
      this.failedJobs++;
      this.logJobFailure(job, error);
    });

    this.queue.on('stalled', (job) => {
      logger.warn('AI推理任务停滞', {
        jobId: job.id,
        data: job.data,
        timestamp: new Date().toISOString()
      });
    });
  }

  /**
   * 启动工作进程池
   */
  async startWorkerPool() {
    logger.info('正在启动AI推理工作进程池...');

    for (let i = 0; i < this.maxWorkers; i++) {
      try {
        const worker = new Worker(path.join(__dirname, 'aiInferenceProcess.cjs'), {
          workerData: {
            workerId: i,
            logLevel: 'info'
          }
        });

        // 工作进程事件监听
        worker.on('online', () => {
          logger.info(`AI推理工作进程 ${i} 已上线`);
        });

        worker.on('message', (message) => {
          this.handleWorkerMessage(i, message);
        });

        worker.on('error', (error) => {
          logger.error(`AI推理工作进程 ${i} 错误:`, error);
          this.restartWorker(i);
        });

        worker.on('exit', (code) => {
          if (code !== 0) {
            logger.error(`AI推理工作进程 ${i} 异常退出，代码: ${code}`);
            this.restartWorker(i);
          }
        });

        this.workers[i] = worker;
        logger.info(`AI推理工作进程 ${i} 启动成功`);

      } catch (error) {
        logger.error(`启动AI推理工作进程 ${i} 失败:`, error);
        throw error;
      }
    }
  }

  /**
   * 处理AI推理任务
   */
  async processAIInferenceJob(job) {
    const startTime = Date.now();
    const { data } = job;

    try {
      logger.info('开始处理AI推理任务', {
        jobId: job.id,
        type: data.type,
        taskId: data.taskId,
        userId: data.userId,
        correlationId: data.correlationId
      });

      // 记录审计日志
      await auditService.logAIInference(
        data.userId,
        data.sessionId,
        data.patientId,
        data.taskId,
        'medical-image-analysis',
        data.imagePath || data.imageData,
        null, // output稍后更新
        'success',
        null,
        startTime,
        0, // duration待定
        data.imageSize || 0,
        0, // output size待定
        {
          jobStarted: new Date().toISOString(),
          workerProcess: true,
          priority: data.priority || QueuePriority.NORMAL
        }
      );

      // 验证任务数据
      this.validateJobData(data);

      // 执行AI推理
      const result = await aiInferenceService.performInference(data);

      const duration = Date.now() - startTime;

      // 更新数据库状态
      if (data.taskId) {
        await this.updateTaskStatus(data.taskId, 'completed', result, duration);
      }

      // 更新审计日志
      await this.updateAuditLog(data, result, duration, 'success');

      logger.info('AI推理任务完成', {
        jobId: job.id,
        taskId: data.taskId,
        duration,
        confidence: result.confidence,
        severity: result.severity
      });

      return {
        success: true,
        result,
        duration,
        timestamp: new Date().toISOString()
      };

    } catch (error) {
      const duration = Date.now() - startTime;

      logger.error('AI推理任务失败', {
        jobId: job.id,
        taskId: data.taskId,
        error: error.message,
        duration,
        attempts: job.attemptsMade
      });

      // 更新数据库状态
      if (data.taskId) {
        await this.updateTaskStatus(data.taskId, 'failed', null, duration, error.message);
      }

      // 更新审计日志
      await this.updateAuditLog(data, null, duration, 'failed', error.message);

      // 记录结构化日志
      structuredLogger.error('AI推理处理失败', {
        jobId: job.id,
        taskId: data.taskId,
        userId: data.userId,
        error: error.message,
        stack: error.stack,
        duration,
        correlationId: data.correlationId
      });

      throw error;
    }
  }

  /**
   * 处理紧急推理任务
   */
  async processUrgentInferenceJob(job) {
    const { data } = job;

    logger.warn('处理紧急AI推理任务', {
      jobId: job.id,
      taskId: data.taskId,
      userId: data.userId,
      urgency: data.urgency
    });

    // 紧急任务使用最高优先级处理
    data.priority = QueuePriority.CRITICAL;
    data.isUrgent = true;

    return await this.processAIInferenceJob(job);
  }

  /**
   * 处理批量推理任务
   */
  async processBatchInferenceJob(job) {
    const { data } = job;
    const startTime = Date.now();

    logger.info('开始处理批量AI推理任务', {
      jobId: job.id,
      batchId: data.batchId,
      imageCount: data.images?.length || 0
    });

    try {
      const results = [];

      for (const imageData of data.images || []) {
        const imageJobData = {
          ...data,
          ...imageData,
          batchMode: true,
          batchId: data.batchId
        };

        // 创建临时job对象用于处理
        const tempJob = { id: job.id, data: imageJobData };
        const result = await this.processAIInferenceJob(tempJob);
        results.push(result);
      }

      const duration = Date.now() - startTime;

      logger.info('批量AI推理任务完成', {
        jobId: job.id,
        batchId: data.batchId,
        imageCount: results.length,
        totalDuration: duration,
        avgDuration: duration / results.length
      });

      return {
        success: true,
        batchId: data.batchId,
        results,
        totalDuration: duration,
        timestamp: new Date().toISOString()
      };

    } catch (error) {
      logger.error('批量AI推理任务失败', {
        jobId: job.id,
        batchId: data.batchId,
        error: error.message
      });

      throw error;
    }
  }

  /**
   * 验证任务数据
   */
  validateJobData(data) {
    if (!data) {
      throw new Error('任务数据为空');
    }

    if (!data.taskId && !data.imagePath && !data.imageData) {
      throw new Error('缺少必需的任务数据: taskId, imagePath 或 imageData');
    }

    if (!data.userId) {
      throw new Error('缺少用户ID');
    }

    // 验证图像数据
    if (data.imageData && typeof data.imageData !== 'string') {
      throw new Error('图像数据格式无效');
    }

    return true;
  }

  /**
   * 更新任务状态
   */
  async updateTaskStatus(taskId, status, result = null, duration = 0, errorMessage = null) {
    try {
      const updateData = {
        status,
        completed_at: new Date().toISOString(),
        processing_duration: duration
      };

      if (result) {
        updateData.ai_result = JSON.stringify(result);
        updateData.confidence_score = result.confidence;
        updateData.severity = result.severity;
        updateData.description = result.description;
      }

      if (errorMessage) {
        updateData.error_message = errorMessage;
      }

      await db.execute(`
        UPDATE scoring_tasks
        SET ${Object.keys(updateData).map(key => `${key} = ?`).join(', ')}
        WHERE task_id = ?
      `, [...Object.values(updateData), taskId]);

      logger.debug('任务状态已更新', {
        taskId,
        status,
        duration,
        hasResult: !!result
      });

    } catch (error) {
      logger.error('更新任务状态失败', {
        taskId,
        status,
        error: error.message
      });
    }
  }

  /**
   * 更新审计日志
   */
  async updateAuditLog(data, result, duration, status, errorMessage = null) {
    try {
      await auditService.logAIInference(
        data.userId,
        data.sessionId,
        data.patientId,
        data.taskId,
        'medical-image-analysis',
        data.imagePath || data.imageData,
        result ? JSON.stringify(result) : null,
        status,
        errorMessage,
        new Date(Date.now() - duration).toISOString(),
        duration,
        data.imageSize || 0,
        result ? JSON.stringify(result).length : 0,
        {
          jobCompleted: new Date().toISOString(),
          workerProcess: true,
          finalStatus: status
        }
      );
    } catch (error) {
      logger.error('更新审计日志失败', {
        taskId: data.taskId,
        error: error.message
      });
    }
  }

  /**
   * 处理工作进程消息
   */
  handleWorkerMessage(workerId, message) {
    switch (message.type) {
      case 'job-completed':
        logger.debug(`工作进程 ${workerId} 完成任务`, message.data);
        break;
      case 'job-failed':
        logger.error(`工作进程 ${workerId} 任务失败`, message.data);
        break;
      case 'heartbeat':
        logger.debug(`工作进程 ${workerId} 心跳`, { timestamp: message.timestamp });
        break;
      default:
        logger.debug(`工作进程 ${workerId} 未知消息`, message);
    }
  }

  /**
   * 重启工作进程
   */
  async restartWorker(workerId) {
    logger.warn(`重启工作进程 ${workerId}`);

    if (this.workers[workerId]) {
      await this.workers[workerId].terminate();
    }

    try {
      const worker = new Worker(path.join(__dirname, 'aiInferenceProcess.js'), {
        workerData: {
          workerId,
          logLevel: 'info',
          restart: true
        }
      });

      worker.on('online', () => {
        logger.info(`重启的工作进程 ${workerId} 已上线`);
      });

      worker.on('error', (error) => {
        logger.error(`重启的工作进程 ${workerId} 错误:`, error);
      });

      this.workers[workerId] = worker;

    } catch (error) {
      logger.error(`重启工作进程 ${workerId} 失败:`, error);
    }
  }

  /**
   * 记录任务完成日志
   */
  logJobCompletion(job, result) {
    logger.info('AI推理任务完成', {
      jobId: job.id,
      type: job.data.type,
      taskId: job.data.taskId,
      duration: result.duration,
      confidence: result.result?.confidence,
      severity: result.result?.severity,
      processedJobs: this.processedJobs,
      failedJobs: this.failedJobs
    });
  }

  /**
   * 记录任务失败日志
   */
  logJobFailure(job, error) {
    logger.error('AI推理任务失败', {
      jobId: job.id,
      type: job.data.type,
      taskId: job.data.taskId,
      error: error.message,
      attempts: job.attemptsMade,
      processedJobs: this.processedJobs,
      failedJobs: this.failedJobs
    });
  }

  /**
   * 设置优雅关闭
   */
  setupGracefulShutdown() {
    const shutdown = async (signal) => {
      logger.info(`收到${signal}信号，正在优雅关闭AI推理工作器...`);

      this.isRunning = false;

      try {
        // 停止接受新任务
        if (this.queue) {
          await this.queue.pause();
        }

        // 等待当前任务完成
        logger.info('等待当前AI推理任务完成...');
        await new Promise(resolve => setTimeout(resolve, 10000)); // 10秒超时

        // 关闭所有工作进程
        for (const [id, worker] of this.workers.entries()) {
          if (worker) {
            logger.info(`关闭工作进程 ${id}`);
            await worker.terminate();
          }
        }

        logger.info('✅ AI推理工作器已优雅关闭', {
          processedJobs: this.processedJobs,
          failedJobs: this.failedJobs,
          uptime: Date.now() - this.startTime
        });

        process.exit(0);

      } catch (error) {
        logger.error('优雅关闭过程中发生错误:', error);
        process.exit(1);
      }
    };

    process.on('SIGTERM', () => shutdown('SIGTERM'));
    process.on('SIGINT', () => shutdown('SIGINT'));
    process.on('SIGUSR2', () => shutdown('SIGUSR2'));
  }

  /**
   * 获取工作器状态
   */
  getStatus() {
    return {
      isRunning: this.isRunning,
      workerCount: this.workers.length,
      maxWorkers: this.maxWorkers,
      processedJobs: this.processedJobs,
      failedJobs: this.failedJobs,
      uptime: this.startTime ? Date.now() - this.startTime : 0,
      queueStatus: this.queue ? 'active' : 'inactive',
      workers: this.workers.map((w, i) => ({
        id: i,
        status: w ? 'running' : 'stopped',
        pid: w?.threadId
      }))
    };
  }
}

// 创建并导出工作器实例
const aiInferenceWorker = new AIInferenceWorker();

export default aiInferenceWorker;